package com.sbtr.common.calculate;

import com.sbtr.common.interfaces.Calculate;
import com.sbtr.exception.BDException;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

@Component
public class CalculateReflectUtil {
    final static Map<String, Method> handleMethod = new HashMap<>();
    final static DataStandardUtils dataStandardUtils = new DataStandardUtils();
    final static DataFilterUtils dataFilterUtils = new DataFilterUtils();
    final static DataExplorationUtils dataExplorationUtils = new DataExplorationUtils();
    final static CalculatorUtils calculatorUtils = new CalculatorUtils();

    public static void main(String[] args) {
//        putMethod();
//        double[] data = {1.0, 2.0, 3.0, 4.0, 5.0};
//        Method method = handleMethod.get("normalizeMinMax");
//        for (int i = 0; i < 100; i++) {
//            long start = System.currentTimeMillis();
//            System.out.println(JSON.toJSONString(exec(method, data)));
//            System.out.println("消耗:" + (System.currentTimeMillis() - start));
//        }

    }

    @PostConstruct
    public void init() {//初始化加载计算函数
        putMethod();
    }

    public Object exec(String methodName, Object... params) throws InvocationTargetException, IllegalAccessException {
        Method method = handleMethod.get(methodName);
        return execMethod(method,params);
    }

    /**
     * 执行方法，第一次慢，后面快
     *
     * @param method
     * @param params
     * @return
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    private static Object execMethod(Method method, Object... params) throws InvocationTargetException, IllegalAccessException {
        if(method==null){
            throw new BDException("不存在该条件函数");
        }
        //TODO 待优化
        if (method.getDeclaringClass().getName().equals("com.sbtr.common.calculate.DataStandardUtils")) {
            return method.invoke(dataStandardUtils, params);
        }
        if (method.getDeclaringClass().getName().equals("com.sbtr.common.calculate.DataFilterUtils")) {
            return method.invoke(dataFilterUtils, params);
        }
        if (method.getDeclaringClass().getName().equals("com.sbtr.common.calculate.DataExplorationUtils")) {
            return method.invoke(dataExplorationUtils, params);
        }
        if (method.getDeclaringClass().getName().equals("com.sbtr.common.calculate.CalculatorUtils")) {
            return method.invoke(calculatorUtils, params);
        }

//        if (method.getDeclaringClass().getName().equals("com.sbtr.common.calculate.DataStandardUtils")) {
//            return method.invoke(dataStandardUtils, params);
//        }
//        if (method.getDeclaringClass().getName().equals("com.sbtr.common.calculate.DataStandardUtils")) {
//            return method.invoke(dataStandardUtils, params);
//        }

        return "无执行类";
    }

    /**
     * 装载方法
     */
    public static void putMethod() {
        Method[] methods = DataStandardUtils.class.getMethods();
        Method[] methods2 = DataFilterUtils.class.getMethods();
        Method[] methods3 = DataExplorationUtils.class.getMethods();
        Method[] methods4 = CalculatorUtils.class.getMethods();

        for (Method method : methods) {
            if (method.isAnnotationPresent(Calculate.class)) {
                Calculate c = method.getAnnotation(Calculate.class);
                handleMethod.put(c.value().getCode(), method);
            }
        }
        for (Method method : methods2) {
            if (method.isAnnotationPresent(Calculate.class)) {
                Calculate c = method.getAnnotation(Calculate.class);
                handleMethod.put(c.value().getCode(), method);
            }
        }
        for (Method method : methods3) {
            if (method.isAnnotationPresent(Calculate.class)) {
                Calculate c = method.getAnnotation(Calculate.class);
                handleMethod.put(c.value().getCode(), method);
            }
        }
        for (Method method : methods4) {
            if (method.isAnnotationPresent(Calculate.class)) {
                Calculate c = method.getAnnotation(Calculate.class);
                handleMethod.put(c.value().getCode(), method);
            }
        }
    }
}
